home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
C
/
Applications
/
Python 1.3.3
/
Python 133 PPC
/
Demo
/
www
/
www.py
< prev
next >
Wrap
Text File
|
1996-05-19
|
10KB
|
440 lines
#! /usr/local/bin/python
# A simple text-based WWW client.
# This is not intended to compete with WWW's LineMode browser, but to
# have an easily modifiable WWW browser, and also to test various
# components like the formatters and protocol interfaces.
import sys
import os
import string
import getopt
from cmd import Cmd
import fmt
import htmllib
import wwwlib
import wwwutil
PAGE_WIDTH = 80 # Page width (for formatter)
# Default locations of logging files
PLACES = '.wwwplaces'
HISTORY = '.wwwhistory'
BOOKMARKS = '.wwwbookmarks'
# Main program
def main():
#
places_file = ''
history_file = ''
bookmarks_file = ''
#
try:
opts, args = getopt.getopt(sys.argv[1:], 'b:h:p:')
except getopt.error, msg:
sys.stdout = sys.stderr
print msg
print 'usage: www [-b file] [-h file] [-p file] [docaddr]'
print '-b file: bookmarks file, default ~/' + BOOKMARKS
print '-h file: history file, default ~/' + HISTORY
print '-p file: places file, default ~/' + PLACES
print 'docaddr: document address, e.g. scheme://host:port/path'
print 'system default:', wwwutil.system_home
if wwwutil.user_home <> wwwutil.system_home:
print 'user default:', wwwutl.user_home
print 'user default settable with $WWW_HOME'
sys.exit(2)
#
for o, a in opts:
if o == '-b': bookmarks_file = a
if o == '-h': history_file = a
if o == '-p': places_file = a
#
if args:
if len(args) > 1:
print 'Too many files -- first one used'
addr = args[0]
else:
addr = ''
#
x = WWWCmd()
#
places = wwwutil.load_file(places_file, PLACES)
if places:
x.places = places
#
history = wwwutil.load_file(history_file, HISTORY)
if history:
if not addr:
addr = history[-1]
history = history[:-1]
x.history = history
#
bookmarks = wwwutil.load_file(bookmarks_file, BOOKMARKS)
if bookmarks is None: bookmarks = []
if wwwutil.user_home and wwwutil.user_home not in bookmarks:
bookmarks.insert(0, wwwutil.user_home)
if wwwutil.system_home and wwwutil.system_home not in bookmarks:
bookmarks.insert(0, wwwutil.system_home)
if bookmarks:
x.bookmarks = bookmarks
#
if not addr:
addr = wwwutil.user_home
ok = x.setaddr(addr)
if not ok and addr <> wwwutil.user_home:
ok = x.setaddr(wwwutil.user_home)
if not ok and addr <> wwwutil.system_home:
ok = x.setaddr(wwwutil.system_home)
if not ok:
x.close()
print '*** Nothing in toplevel menu ***'
return
#
try:
try:
x.cmdloop()
except SystemExit:
pass
finally:
wwwutil.save_file(x.bookmarks, bookmarks_file, BOOKMARKS)
wwwutil.save_file(x.history + [x.cur_addr], \
history_file, HISTORY)
wwwutil.save_file(x.places, places_file, PLACES)
# Class handling the command loop
class WWWCmd(Cmd):
#
def __init__(self):
Cmd.__init__(self)
self.prompt = 'Which anchor? (h for help) '
self.cur_addr = ''
self.cur_data = ''
self.cur_title = ''
self.cur_anchors = []
self.cur_isindex = 0
self.bookmarks = []
self.history = []
self.places = {}
#
def close(self):
pass
#
def do_add(self, arg):
if self.cur_addr in self.bookmarks:
print '*** Already in list of marks: m',
print self.bookmarks.index(self.cur_addr)+1
return
self.bookmarks.append(self.cur_addr)
print 'Added as m', len(self.bookmarks)
do_a = do_add
#
def do_back(self, arg):
if not self.history:
print '*** No more levels'
return
addr = self.history[-1]
del self.history[-1]
if not self.setaddr(addr):
print '*** Lost that link -- try again'
do_b = do_back
#
def do_find(self, arg):
if not self.cur_isindex:
print '*** Not an index'
return
words = string.split(arg)
if not words:
print '*** What do you want to find?'
return
scheme, host, port, path, search, anchor = \
wwwlib.parse_addr(self.cur_addr)
search = '?' + string.joinfields(words, '+')
addr = wwwlib.unparse_addr(scheme,host,port,path,search,'')
self.follow(addr)
do_f = do_find
#
def do_goto(self, arg):
self.follow(arg)
do_g = do_goto
#
do_h = Cmd.do_help.im_func
# XXX Very unsatisfactory hack! It used to read Cmd.do_help but
# XXX since 0.9.9 that yields an <unbound method> object which
# XXX can't be passed on transparently to a derived class
# XXX in this way. (Maybe Python should be changed?)
#
def do_info(self, arg):
print self.cur_addr
if self.cur_isindex:
print '<ISINDEX>'
if self.cur_title:
print '<TITLE>' + self.cur_title + '</TITLE>'
do_i = do_info
#
def do_list(self, arg):
if not self.cur_anchors:
print '*** No anchors here'
return
verbose = (arg == '-v')
real_stdout = sys.stdout
pipe = sys.stdout = os.popen('${PAGER-more}', 'w')
try:
for i in range(len(self.cur_anchors)):
label = `[i+1]`
addr = self.cur_anchors[i]
if verbose:
print label, addr
label = ' '*len(label)
full = wwwlib.full_addr(self.cur_addr, \
addr, self.cur_isindex)
if verbose and full <> addr:
print label, full
if self.places.has_key(full):
t = self.places[full][0]
else:
t = None
if t:
print label, t
elif not verbose:
print label, addr
sys.stdout = real_stdout
except IOError, msg:
sys.stdout = real_stdout
print '*** IOError:', msg
except KeyboardInterrupt:
sys.stdout = real_stdout
print
sts = pipe.close()
if sts:
print '*** Pager exit status:', sts
do_l = do_list
#
def do_mark(self, arg):
list = self.bookmarks
verbose = 0
if arg == '-v':
verbose = 1
words = []
else:
words = string.split(arg)
if words:
try:
i = string.atoi(words[0])
except string.atoi_error:
print '*** usage: m(ark) [number]'
return
if 1 <= i <= len(list):
self.follow(list[i-1])
else:
print '*** recall index out of range',
print '(' + `1` + '...' + `len(list)` + ')'
return
for i in range(len(list)):
label = 'm ' + `i+1`
addr = list[i]
title, exits = self.places[addr]
if title:
print label, title
else:
print label, addr
if not verbose:
continue
label = ' '*len(label)
if title:
print label, addr
label = label + ' (-->'
for exit in exits:
if i+1 >= len(list) or exit != list[i+1]:
t = self.places[exit][0]
if t:
print label, t + ')'
else:
print label, exit + ')'
do_m = do_mark
#
def do_places(self, arg):
real_stdout = sys.stdout
pipe = sys.stdout = os.popen('${PAGER-more}', 'w')
try:
for addr in self.places.keys():
print addr
title, exits = self.places[addr]
if title:
print '(' + title + ')'
for exit in exits:
print '-->', exit
t = self.places[exit][0]
if t:
print ' ', '(' + t + ')'
sys.stdout = real_stdout
except IOError, msg:
sys.stdout = real_stdout
print '*** IOError:', msg
except KeyboardInterrupt:
sys.stdout = real_stdout
print
sts = pipe.close()
if sts:
print '*** Pager exit status:', sts
#
def do_quit(self, arg):
print '[Goodbye]'
raise SystemExit
do_EOF = do_q = do_quit
#
def do_recall(self, arg):
verbose = 0
hlist = self.history + [self.cur_addr]
if arg == '-v':
verbose = 1
words = []
else:
words = string.split(arg)
if words:
try:
i = string.atoi(words[0])
except string.atoi_error:
print '*** usage: r(ecall) [number]'
return
if 1 <= i <= len(hlist):
self.follow(hlist[i-1])
else:
print '*** recall index out of range',
print '(' + `1` + '...' + `len(hlist)` + ')'
return
for i in range(len(hlist)):
label = 'r ' + `i+1`
addr = hlist[i]
title, exits = self.places[addr]
if title:
print label, title
else:
print label, addr
if not verbose:
continue
label = ' '*len(label)
if title:
print label, addr
label = label + ' (-->'
for exit in exits:
if i+1 >= len(hlist) or exit != hlist[i+1]:
t = self.places[exit][0]
if t:
print label, t + ')'
else:
print label, exit + ')'
do_r = do_recall
#
def do_source(self, arg):
pipe = os.popen('${PAGER-more}', 'w')
try:
pipe.write(self.cur_data)
except IOError, msg:
print '*** IOError:', msg
except KeyboardInterrupt:
print
sts = pipe.close()
if sts:
print '*** Pager exit status:', sts
do_s = do_source
#
def do_top(self, arg):
self.show()
do_t = do_top
#
def default(self, line):
try:
i = string.atoi(string.strip(line))
except string.atoi_error:
if self.cur_isindex:
self.do_find(line)
else:
print '*** Unknown command, type h for help'
return
if not self.cur_anchors:
print '*** No anchors here, type u to go up a level'
return
if not 1 <= i <= len(self.cur_anchors):
print '*** Number out of anchor range [1-' + \
`len(self.cur_anchors)` + '] (l lists anchors)'
return
self.follow(self.cur_anchors[i-1])
#
def follow(self, addr):
parent = self.cur_addr
if self.setaddr(addr):
self.history.append(parent)
exits = self.places[parent][1]
if self.cur_addr in exits:
exits.remove(self.cur_addr)
exits.append(self.cur_addr)
self.prompt = self.baseprompt + '(b=back, h=help) '
#
def setaddr(self, addr):
addr = wwwlib.full_addr(self.cur_addr, addr, \
self.cur_isindex)
try:
data = wwwlib.get_document(addr)
except (wwwlib.BadAddress, IOError), msg:
print '***', addr, ':', msg
return 0
self.cur_addr = addr
self.cur_data = data
self.cur_title = ''
self.cur_anchors = []
self.cur_isindex = 0
self.show()
#
if not self.places.has_key(self.cur_addr):
exits = []
else:
exits = self.places[self.cur_addr][1]
self.places[self.cur_addr] = (self.cur_title, exits)
#
if self.cur_isindex and self.cur_anchors:
prompt = 'Keyword or anchor? '
elif self.cur_isindex:
prompt = 'Find keyword? '
elif self.cur_anchors:
prompt = 'Which anchor? '
else:
prompt = 'What now? '
self.baseprompt = prompt
self.prompt = prompt + '(q == quit, h == help) '
return 1
#
def show(self):
pipe = os.popen('${PAGER-more}', 'w')
fmtr = fmt.WritingFormatter(pipe, PAGE_WIDTH)
parser = htmllib.FormattingParser(fmtr, \
htmllib.NullStylesheet)
try:
parser.feed(self.cur_data)
parser.close()
pipe.write('\n\n')
except IOError, msg:
print '*** IOError:', msg
except KeyboardInterrupt:
print
sts = pipe.close()
if sts:
print '*** Pager exit status:', sts
self.cur_anchors = parser.anchors
self.cur_title = parser.title
self.cur_isindex = parser.isindex
try:
main()
except KeyboardInterrupt:
print
print '[Intr]'